package com.ims.filter;

import com.ims.service.impl.UserServiceImpl;
import com.ims.util.JwtUtil;
import com.ims.util.RedisUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import redis.clients.jedis.Jedis;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author: zk
 * @date: 2022/9/1 12:30
 */
@Component
public class LoginFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserServiceImpl userService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        if (requestURI.startsWith("/user/login")) {
            chain.doFilter(request, response);
            return;
        }

        // 从请求头中获取token字符串
        String accessToken = request.getHeader("Authorization");
        if (!StringUtils.hasText(accessToken)) {
            Jedis jedis = new Jedis(RedisUtil.host, RedisUtil.port);
            accessToken = jedis.get("accessToken");
            jedis.close();
        }
        System.out.println("\n\n filter -> token : " + accessToken + "\n\n");

        // 解析token
        Claims claims = jwtUtil.parse(accessToken);

        // 如果token不合法
        if (claims == null) {
            chain.doFilter(request, response);
            return;
        }

        // token是否过期
        if (jwtUtil.tokenExpired(accessToken)) {
            // 处理token过期
            boolean refresh = handleTokenExpired(request, response);
            // 刷新token失败
            if (!refresh) {
                chain.doFilter(request, response);
                return;
            }
        }

        {
            // 从JWT中提取出之前存储好的用户名
            String username = claims.getSubject();
            // 查询出用户对象
            UserDetails user = userService.loadUserByUsername(username);
            // 手动组装一个认证对象
            Authentication authentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        chain.doFilter(request, response);
    }

    /**
     * token过期处理
     * @param request
     * @param response
     */
    private Boolean handleTokenExpired(HttpServletRequest request, HttpServletResponse response) {
        // 获取refreshToken
        Jedis jedis = new Jedis(RedisUtil.host, RedisUtil.port);
        String refreshToken = jedis.get("refreshToken");

        // 解析refreshToken
        Claims claims = jwtUtil.parse(refreshToken);
        // 判断refreshToken是否合法
        if (claims == null) {
            return false;
        }

        // 判断refreshToken是否过期
        if (jwtUtil.tokenExpired(refreshToken)) {
            // 过期了，重新登陆
            return false;
        }

        // 重新签发token
        String subject = claims.getSubject();
        String accessToken = jwtUtil.generateAccessToken(subject);
        refreshToken = jwtUtil.generateRefreshToken(subject);

        response.setHeader("Authorization", accessToken);

        jedis.set("accessToken", accessToken);
        jedis.set("refreshToken", refreshToken);
        jedis.close();
        return true;
    }
}
